﻿#include "stdafx.h"
#if _QG_USE_D11
#include "qg_d11_dev.h"
#include "qg_d11_mtrl.h"
#include "qg_d11_cnv.h"
#include "qg_trace.h"

// 재질 바인드
bool D11Device::_BindMtrl(ksize_t count) throw()
{
	// 래스터라이저
	if (_sprn->bd_rasz)
	{
		_sprn->bd_rasz = false;

		if (!_sprn->m_rasz)
		{
			_context->RSSetState(NULL);
			_context->OMSetDepthStencilState(NULL, 0);
		}
		else
		{
			ID3D11RasterizerState* rs = (ID3D11RasterizerState*)_sprn->m_rasz->GetDescription();
			_context->RSSetState(rs);
			_context->OMSetDepthStencilState(((D11Rasz*)_sprn->m_rasz)->GetDepthStencilState(), 0);
		}
	}

	// 블렌드
	if (_sprn->bd_blnd)
	{
		_sprn->bd_blnd = false;

		if (!_sprn->m_blnd)
			_context->OMSetBlendState(NULL, NULL, 0xFFFFFFFF);
		else
		{
			ID3D11BlendState* bs = (ID3D11BlendState*)_sprn->m_blnd->GetDescription();
			_context->OMSetBlendState(bs, NULL, 0xFFFFFFFF);
		}
	}

	// 텍스쳐와 샘플러
	ID3D11ShaderResourceView* ltx[QGSGTEX_MAX_VALUE];
	ID3D11SamplerState* lss[QGSGTEX_MAX_VALUE];
	ksize_t ctx, css, i;

	for (ctx = css = i = 0; i < count; i++)
	{
		ltx[i] = _sprn->m_tex[i] ? (ID3D11ShaderResourceView*)_sprn->m_tex[i]->GetDescription() : NULL;

		if (_sprn->bd_tex[i])
		{
			_sprn->bd_tex[i] = false;
			ctx++;
		}

		lss[i] = _sprn->m_splr[i] ? (ID3D11SamplerState*)_sprn->m_splr[i]->GetDescription() : NULL;

		if (_sprn->bd_splr[i])
		{
			_sprn->bd_splr[i] = false;
			css++;
		}
	}

	if (ctx > 0)
		_context->PSSetShaderResources(0, count, ltx);

	if (css > 0)
		_context->PSSetSamplers(0, count, lss);

	//
	return true;
}

//
qgRasz* D11Device::_RoamImplRasz(const qgRaszData& data)
{
	D11Rasz* rasz = kobj_new(D11Rasz);

	if (!rasz->_CreateRasz(data, this))
	{
		rasz->Unload();
		rasz = NULL;
	}

	return rasz;
}

//
qgBlnd* D11Device::_RoamImplBlnd(const qgBlndData& data)
{
	D11Blnd* blnd = kobj_new(D11Blnd);

	if (!blnd->_CreateBlnd(data, this))
	{
		blnd->Unload();
		blnd = NULL;
	}

	return blnd;
}

//
qgSplr* D11Device::_RoamImplSplr(const qgSplrData& data)
{
	D11Splr* splr = kobj_new(D11Splr);

	if (!splr->_CreateSplr(data, this))
	{
		splr->Unload();
		splr = NULL;
	}

	return splr;
}


//////////////////////////////////////////////////////////////////////////
// 래스터라이저
KIMPL_SUBCLASS(D11Rasz, "D11Rasz");

//
D11Rasz::D11Rasz() throw()
{
}

//
D11Rasz::~D11Rasz() throw()
{
	ID3D11RasterizerState* rs = (ID3D11RasterizerState*)_node_desc;
	kunk_release(rs);

	kunk_release(_dss);
}

//
bool D11Rasz::_CreateRasz(const qgRaszData& data, D11Device* dev)
{
	_data = data;

	// 래스터라이저
	D3D11_RASTERIZER_DESC rd;
	rd.FillMode = // POINT 지원 안하네?
		data.fill == QGFILL_SOLID ? D3D11_FILL_SOLID :
		data.fill == QGFILL_WIRE ? D3D11_FILL_WIREFRAME : D3D11_FILL_WIREFRAME;
	rd.CullMode =
		data.cull == QGCULL_BACK ? D3D11_CULL_BACK :
		data.cull == QGCULL_FRONT ? D3D11_CULL_FRONT : D3D11_CULL_NONE;
	rd.FrontCounterClockwise = false;
	rd.DepthBias = data.dbias;
	rd.DepthBiasClamp = data.dclamp;
	rd.SlopeScaledDepthBias = data.slope_scale;
	rd.DepthClipEnable = true;
	rd.ScissorEnable = false;
	rd.MultisampleEnable = false;
	rd.AntialiasedLineEnable = false;

	ID3D11RasterizerState* rs;

	if (FAILED(dev->GetDevice()->CreateRasterizerState(&rd, &rs)))
	{
		kobj_tracep(KLV_ERROR, KERR_FAIL);
		return false;
	}

	// 뎁스 스텐실
	D3D11_DEPTH_STENCIL_DESC dsd = {0, };
	dsd.DepthEnable = data.dfunc != QGCOP_NONE;
	dsd.DepthWriteMask = data.dwrite ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
	dsd.DepthFunc = D11Convert::ComparisonOp(data.dfunc);

	ID3D11DepthStencilState* dss;

	if (FAILED(dev->GetDevice()->CreateDepthStencilState(&dsd, &dss)))
	{
		rs->Release();
		kobj_tracep(KLV_ERROR, KERR_FAIL);
		return false;
	}

	// rasz는 desc에 ds는 그냥 보관
	_node_desc = (kuintptr)rs;
	_dss = dss;

	return true;
}


//////////////////////////////////////////////////////////////////////////
// 블렌드
KIMPL_SUBCLASS(D11Blnd, "D11Blnd");

//
D11Blnd::D11Blnd() throw()
{
}

//
D11Blnd::~D11Blnd() throw()
{
	ID3D11BlendState* bs = (ID3D11BlendState*)_node_desc;
	kunk_release(bs);
}

//
bool D11Blnd::_CreateBlnd(const qgBlndData& data, D11Device* dev)
{
	_data = data;

	// 블렌드
	D3D11_BLEND_DESC bd = {0, };

	// 스테이지 1개만 지원함
	if (data.blend.op != QGBLO_NONE)
	{
		bd.RenderTarget[0].BlendEnable = true;
		bd.RenderTarget[0].BlendOp = D11Convert::BlendOp(data.blend.op);
		bd.RenderTarget[0].SrcBlend = D11Convert::BlendValue(data.blend.src);
		bd.RenderTarget[0].DestBlend = D11Convert::BlendValue(data.blend.dest);

		if (data.alpha.op == QGBLO_NONE)
		{
			bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
			bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
			bd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
		}
		else
		{
			bd.RenderTarget[0].BlendOpAlpha = D11Convert::BlendOp(data.alpha.op);
			bd.RenderTarget[0].SrcBlendAlpha = D11Convert::BlendValue(data.alpha.src);
			bd.RenderTarget[0].DestBlendAlpha = D11Convert::BlendValue(data.alpha.dest);
		}

		bd.RenderTarget[0].RenderTargetWriteMask = (UINT8)data.mask;
	}

	ID3D11BlendState* bs;

	if (FAILED(dev->GetDevice()->CreateBlendState(&bd, &bs)))
	{
		kobj_tracep(KLV_ERROR, KERR_FAIL);
		return false;
	}

	_node_desc = (kuintptr)bs;

	return true;
}


//////////////////////////////////////////////////////////////////////////
// 샘플러
KIMPL_SUBCLASS(D11Splr, "D11Splr");

//
D11Splr::D11Splr() throw()
{
}

//
D11Splr::~D11Splr() throw()
{
	ID3D11SamplerState* bs = (ID3D11SamplerState*)_node_desc;
	kunk_release(bs);
}

//
bool D11Splr::_CreateSplr(const qgSplrData& data, D11Device* dev)
{
	_data = data;

	// 블렌드
	D3D11_SAMPLER_DESC sd;

	sd.Filter = D11Convert::Filter(data.filt);
	sd.AddressU = D11Convert::Address(data.addru);
	sd.AddressV = D11Convert::Address(data.addrv);
	sd.AddressW = D11Convert::Address(data.addrw);
	sd.MipLODBias = data.lodbias;
	sd.MaxAnisotropy = 1;	//@ 시스템 설정으로 처리할 것
	sd.ComparisonFunc = D11Convert::ComparisonOp(data.cop);
	(tpl::Color&)sd.BorderColor = tpl::Color(data.border);
	sd.MinLOD = data.lodrange.min;
	sd.MaxLOD = data.lodrange.max;

	ID3D11SamplerState* ss;

	if (FAILED(dev->GetDevice()->CreateSamplerState(&sd, &ss)))
	{
		kobj_tracep(KLV_ERROR, KERR_FAIL);
		return false;
	}

	_node_desc = (kuintptr)ss;

	return true;
}

#endif	// _QG_USE_D11
